package com.itextpdf.local.ess.Signature;
import com.itextpdf.local.ess.predefine.SealStandard;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;

import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;

public class ESSEmptyContainer {
    static class MyExternalSignatureContainer implements ExternalSignatureContainer {
        protected byte[] sig;
        public MyExternalSignatureContainer(byte[] sig) {
            this.sig = sig;
        }
        public byte[] sign(InputStream is) {
            return sig;
        }
        public byte[] getHash() {
            return null;
        }
        public void setHashAlgorithm(String hashAlgorithm){
        }
        @Override
        public void modifySigningDictionary(PdfDictionary signDic) {
        }
    }
    static class EmptyContainer implements ExternalSignatureContainer {
        protected byte[] toSign;
        protected byte[] hash;
        protected String hashAlgorithm;
        public EmptyContainer() {
        }
        public byte[] sign(InputStream is) {
            try {
                ExternalDigest digest = getDigest();
                hash = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
                return new byte[0];
            } catch (IOException | GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        }
        public byte[] getHash() {
            return hash;
        }
        public void setHashAlgorithm(String hashAlgorithm){
            this.hashAlgorithm = hashAlgorithm;
        }
        @Override
        public void modifySigningDictionary(PdfDictionary pdfDictionary) {
            pdfDictionary.put(PdfName.FILTER, PdfName.ADOBE_PPKMS);
            pdfDictionary.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED);
        }
    }

    public static byte[] getOscp(Certificate[] chain) {
        byte[] ocsp = null;
        OcspClient ocspClient = new OcspClientBouncyCastle(new OCSPVerifier(null, null));
        if (chain.length >= 2) {
            ocsp = ocspClient.getEncoded((X509Certificate)chain[0], (X509Certificate)chain[1], null);
        }
        return ocsp;
    }

    public static PdfPKCS7 getPkcs(Certificate[] certChain) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
        //noinspection ConstantConditions
        return new PdfPKCS7(null, certChain, getHashAlgorithm(certChain), null, getDigest(), false);
    }
    public static ExternalDigest getDigest() {
        return new ExternalDigest() {
            public MessageDigest getMessageDigest(String hashAlgorithm)
                    throws GeneralSecurityException {
                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
            }
        };
    }
    public static TSAClient getTsa() {
        return new TSAClientBouncyCastle("http://timestamp.digicert.com", null, null, 4096, "SHA-512");
    }

    public static String getHashAlgorithm(Certificate[] certChain) {
        String hashAlgorithm = "SHA256";
        try {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
            X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(
                    new ByteArrayInputStream(certChain[0].getEncoded()));
            switch (x509Certificate.getSigAlgName()){
                case "SM3WITHSM2":
                    hashAlgorithm = "SM3";
                    break;
                case "SHA1WITHRSA":
                    hashAlgorithm = "SHA1";
                    break;
                case "SHA256WITHRSA":
                    hashAlgorithm = "SHA256";
                    break;
            }
        } catch (CertificateException | NoSuchProviderException e) {
            e.printStackTrace();
        }
        return hashAlgorithm;
    }

    public static String getHashAlgorithm(SealStandard sealStandard) {
        String hashAlgorithm = "SHA256";
        switch (sealStandard){
            case AKUK:
            case GBUK:
            case AKPFX:
            case GBPFX:
            case AKJMJ:
            case GBJMJ:
                hashAlgorithm = "SM2";
                break;
            case ESSRSAUK:
            case ESSRSAPFX:
            case ESSRSAJMJ:
                hashAlgorithm = "SHA256";
                break;
            default:
                break;
        }
        return hashAlgorithm;
    }
}
